﻿/************************************************************************
 * AIDE - Automata Identification Engine
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     AIDE\OnlineAlgo\IAs\LearningPurpose_IA.cs
 * Description  :     Implement the learning purpose for IA learning
 * Change log   :     -Oct 2013: Initial draft
 * To Do        :     -it is not fully imeplemented!!
 ************************************************************************/

using System;
using System.Collections.Generic;
using SMLib.Automata.IA;
using SMLib.Automata.Base;


namespace AIDE.Learning.IA_Learning
{
    /// <summary>
    /// Provide the learning purpose for IA learner (as a filter)
    /// <remarks>
    /// Note that Learnin Purpose is different from Testing Purpose. The first one can be implemented as a filter (black box filter) but
    /// the later should be used as an automata an we have to combine it with the main specification.
    /// When we learn a model with a purpose P, it would be the same if we use P as the testing purpose or not because 
    /// it is already combined with P.
    /// </remarks>
    /// </summary>
    public class LearningPurpose_IA : IBlackBox_IA
    {
        /// <summary>
        /// the learning purpose
        /// </summary>
        InterfaceAutomaton ia;

        /// <summary>
        /// The current state (in learning purpose)
        /// </summary>
        InterfaceAutomaton.IA_State currState;
        
        /// <summary>
        /// A string symbol "*" representing every symbol
        /// </summary>
        StringSymbol star;

        /// <summary>
        /// the system under learning
        /// </summary>
        IBlackBox_IA sul;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ia">the learning purpose</param>
        /// <param name="sut">the system under learning</param>
        public LearningPurpose_IA(InterfaceAutomaton ia, IBlackBox_IA sul)
        {
            star = new StringSymbol("*");
            this.ia = ia;
            this.sul = sul;
            //* the -input- alphabet of learning purpose should be subset of the main system
            foreach (ISymbol s in ia.InputAlphabet.AllSymbols())
                if (!sul.InputAlphabet.Contains(s))
                    throw new Exception("Alphabet doesn't match!");
        }


        #region IBlackBox_IA Members

        public void Reset()
        {
            currState = (InterfaceAutomaton.IA_State)ia.InitialState;
            sul.Reset();
        }


        public void Perform(ISymbol input)
        {
            foreach (InterfaceAutomaton.IA_Step t in currState.Transitions)
            {
                if (t.Equals(star) || t.Equals(input))
                {
                    sul.Perform(input);
                    currState = (InterfaceAutomaton.IA_State)t.Destination;
                    break;
                }
            }
        }

        public bool EventAvailable()
        {
            return sul.EventAvailable();
        }

        public ISymbol Event()
        {
            ISymbol o = sul.Event();
            foreach (InterfaceAutomaton.IA_Step t in currState.Transitions)
            {
                if (t.StepType == InterfaceAutomaton.IA_Step.Step_Type.EVENT && t.Equals(star))
                {
                    currState = (InterfaceAutomaton.IA_State)t.Destination;
                    break;
                }
            }
            return o;
        }

        public Alphabet InputAlphabet
        {
            get { return ia.InputAlphabet; }
        }

        #endregion
    }
}
